﻿using System;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using System.Web;
using Microsoft.SharePoint.WebPartPages;
using System.Web.UI.WebControls.WebParts;
using System.Xml;
using System.Collections.Generic;

namespace SharePointExtendedDetailsFeature
{
    public class ExtendedDetails
    {
        #region Properties

        public string SiteUrl { get; set; }
        public string ListId { get; set; }

        #endregion

        #region Worker Methods

        public void ProcessListItem()
        {
            // Add the script webparts if needed
            AddScriptWebParts();

            // Get a reference to the details list
            SPList detailsList = SPContext.Current.Site.RootWeb.Lists.TryGetList(Constants.ListName);

            // If the list is present process the item
            if (detailsList != null)
            {
                // Variable to hold the GUID and Title we will look up
                string lookupGuid = String.Empty;
                string lookupTitle = String.Empty;

                // If SiteUrl is populated look up site and get GUID, otherwise its a List and we'll use the ID provided
                if (!String.IsNullOrEmpty(this.SiteUrl))
                {
                    using (SPSite site = new SPSite(this.SiteUrl))
                    {
                        using (SPWeb web = site.OpenWeb())
                        {
                            lookupGuid = web.ID.ToString();
                            lookupTitle = "Site: " + web.Title;
                        }
                    }
                }
                else
                {
                    lookupGuid = this.FormatListId();
                    lookupTitle = "List: " + SPContext.Current.Web.Lists[new Guid(lookupGuid)].Title;
                }

                // Create SPQuery and query the list
                SPQuery query = new SPQuery();
                query.Query = "<Where><Eq><FieldRef Name='" + Constants.FieldGuid + "' /><Value Type='Text'>" + lookupGuid + "</Value></Eq></Where>";
                SPListItemCollection items = detailsList.GetItems(query);
                if (items.Count == 0)
                {
                    if (IsUserContributeOrHigher())
                        SPUtility.Redirect(SPContext.Current.Site.Url + Constants.NewItemPageUrl, SPRedirectFlags.Default, HttpContext.Current, "IsDlg=1&NewFormUrl=" + detailsList.DefaultNewFormUrl + "&ObjectGuid=" + lookupGuid + "&Title=" + lookupTitle);
                    else
                        SPUtility.Redirect(SPContext.Current.Site.Url + Constants.NoItemPageUrl, SPRedirectFlags.Default, HttpContext.Current, null);
                }
                else
                {
                    SPUtility.Redirect(detailsList.DefaultDisplayFormUrl, SPRedirectFlags.Default, HttpContext.Current, "IsDlg=1&ID=" + items[0].ID);
                }
            }
            else
            {
                throw new SPException("Could not locate list: " + Constants.ListName);
            }
        }

        /// <summary>
        /// Adds content editor webpart to New and Edit forms to populate fields and set as readonly
        /// This must be done outside of feature activation
        /// </summary>
        private void AddScriptWebParts()
        {
            Guid siteGuid = SPContext.Current.Site.ID;

            // Run in elevated priv since the first user hitting these pages may not have permissions to add webparts
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPSite site = new SPSite(siteGuid))
                {
                    using (SPWeb web = site.RootWeb)
                    {
                        // Turn on allow unsafe updates
                        web.AllowUnsafeUpdates = true;

                        // Get a reference to the details list
                        SPList detailsList = web.Lists.TryGetList(Constants.ListName);

                        if (detailsList != null)
                        {
                            // Get all the forms we need to add webparts for
                            Dictionary<string, SPFile> forms = new Dictionary<string, SPFile>();
                            forms.Add("NEW", site.RootWeb.GetFile(detailsList.DefaultNewFormUrl));
                            forms.Add("EDIT", site.RootWeb.GetFile(detailsList.DefaultEditFormUrl));
                            forms.Add("DISPLAY", site.RootWeb.GetFile(detailsList.DefaultDisplayFormUrl));

                            // Iterate through the forms and add webparts if needed
                            foreach (KeyValuePair<string, SPFile> form in forms)
                            {
                                using (SPLimitedWebPartManager wpm = form.Value.GetLimitedWebPartManager(System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared))
                                {
                                    // create our Content Editor web part
                                    ContentEditorWebPart wp = GenerateWebPart(form.Key);

                                    // only execute this code if there is a single web part (the default for this list)
                                    if (wpm.WebParts.Count == 1)
                                    {
                                        // add the web part to the Main zone in position 2
                                        wpm.AddWebPart(wp, "Main", 2);
                                    }
                                }
                            }
                        }

                        // Save changes
                        web.Update();

                        // Turn off allow unsafe updates
                        web.AllowUnsafeUpdates = false;
                    }
                }
            });
        }

        #endregion

        #region Helper Methods

        /// <summary>
        /// Checks if the user is Contribute or higher
        /// </summary>
        /// <returns></returns>
        private bool IsUserContributeOrHigher()
        {
            using (SPWeb web = SPContext.Current.Web)
            {
                // Get all user's roles
                SPRoleDefinitionBindingCollection usersRoles = web.AllRolesForCurrentUser;

                // Role definitions to compare with user's roles
                SPRoleDefinitionCollection roleDefinitions = web.RoleDefinitions;

                // Checks user's permission level
                if (usersRoles.Contains(roleDefinitions["Contribute"]))
                    return true;
                if (usersRoles.Contains(roleDefinitions["Design"]))
                    return true;
                if (usersRoles.Contains(roleDefinitions["Full Control"]))
                    return true;
                else
                    return false;
            }
        }

        /// <summary>
        /// Generates the Content Editor Web part to place the javascript on our forms
        /// </summary>
        /// <param name="pageForPart"></param>
        /// <returns></returns>
        private ContentEditorWebPart GenerateWebPart(string pageForPart)
        {
            // create our Content Editor web part
            ContentEditorWebPart wp = new ContentEditorWebPart();

            // set basic properties along with the title
            wp.ChromeType = PartChromeType.None;
            wp.Title = Constants.ContentEditorWebPartTitle;

            XmlDocument xmlDoc = new XmlDocument();
            XmlElement xmlElement = xmlDoc.CreateElement("Root");
            if (pageForPart.ToUpper() == "EDIT")
                xmlElement.InnerText = Constants.EditFormJavascript;
            else if (pageForPart.ToUpper() == "NEW")
                xmlElement.InnerText = Constants.NewFormJavascript;
            else
                xmlElement.InnerText = Constants.DisplayFormJavascript;
            wp.Content = xmlElement;
            wp.Content.InnerText = xmlElement.InnerText;

            return wp;
        }

        /// <summary>
        /// Checks both querystring parameters, if both or null/empty there was a problem
        /// </summary>
        /// <returns></returns>
        public bool IsPageValid()
        {
            return (!String.IsNullOrEmpty(this.SiteUrl) || !String.IsNullOrEmpty(this.ListId));
        }

        /// <summary>
        /// Formats the ListId from the querystring to remove the brackets
        /// </summary>
        /// <returns></returns>
        private string FormatListId()
        {
            return this.ListId.Replace("{","").Replace("}","");
        }

        #endregion
    }
}
